home *** CD-ROM | disk | FTP | other *** search
/ GFX Sensations 1 / Graphic Sensations - Volume 1.iso / tools / amiga / 3d_tools / irit40s.lha / Irit / prsr_lib / iritprsr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-02  |  55.2 KB  |  1,936 lines

  1. /*****************************************************************************
  2. * Generic parser for the "Irit" solid modeller.                     *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 0.2, Sep. 1991   *
  5. *****************************************************************************/
  6.  
  7. #ifdef USE_VARARGS
  8. #include <varargs.h>
  9. #else
  10. #include <stdarg.h>
  11. #endif /* USE_VARARGS */
  12.  
  13. #include <stdio.h>
  14. #include <ctype.h>
  15. #include <math.h>
  16. #include <string.h>
  17. #include <setjmp.h>
  18. #include "irit_sm.h"
  19. #include "iritprsr.h"
  20. #include "allocate.h"
  21. #include "attribut.h"
  22. #include "irit_soc.h"
  23.  
  24. #define UNGET_STACK_SIZE    5             /* Internal stack size. */
  25. #define CONVEX_EPSILON        1e-3
  26. #define NORMAL_MIN_VALID_LEN    0.03
  27. #define ZERO_NUM_EPSILON    1e-15
  28.  
  29. #define MAX_NUM_OPEN_FILES    10        /* Maximum number of open files. */
  30.  
  31. typedef enum {              /* List of all possible tokens enumerated. */
  32.     TOKEN_NONE,
  33.  
  34.     TOKEN_OPEN_PAREN,
  35.     TOKEN_CLOSE_PAREN,
  36.  
  37.     TOKEN_E1,
  38.     TOKEN_P1,
  39.     TOKEN_E2,
  40.     TOKEN_P2,
  41.     TOKEN_E3,
  42.     TOKEN_P3,
  43.     TOKEN_E4,
  44.     TOKEN_P4,
  45.     TOKEN_E5,
  46.     TOKEN_P5,
  47.  
  48.     TOKEN_NUMBER,
  49.     TOKEN_STRING,
  50.     TOKEN_POINT,
  51.     TOKEN_VECTOR,
  52.     TOKEN_MATRIX,
  53.     TOKEN_CTLPT,
  54.     TOKEN_VERTEX,
  55.     TOKEN_POLYGON,
  56.     TOKEN_POLYLINE,
  57.     TOKEN_POINTLIST,
  58.     TOKEN_OBJECT,
  59.     TOKEN_COLOR,
  60.     TOKEN_RGB,
  61.     TOKEN_INTERNAL,
  62.     TOKEN_NORMAL,
  63.     TOKEN_PLANE,
  64.     TOKEN_CURVE,
  65.     TOKEN_SURFACE,
  66.  
  67.     TOKEN_OTHER    = 100,            /* Probably names & numbers. */
  68.     TOKEN_QUOTED,            /* A quoted string. */
  69.  
  70.     TOKEN_EOF = -1
  71. } TokenType;
  72.  
  73. struct OpenedFile {
  74.     FILE *f;
  75.     int IsPipe;
  76. } OpenedFiles[MAX_NUM_OPEN_FILES];
  77.  
  78. static IritPrsrErrType
  79.     GlblParserError = IP_NO_ERR;            /* Last err # found. */
  80. static int
  81.     GlblFlattenObjects = TRUE,       /* If input list hierarchy is to be kept. */
  82.     GlblReadOneObject = FALSE,        /* If only one object is to be read. */
  83.     GlblToken =    0,              /* Used by the parser, to unget token. */
  84.     GlblLineCount = 1;             /* Used to locate errors in input file. */
  85. static char
  86.     GlblTokenError[LINE_LEN_LONG],          /* Last token error was found. */
  87.     GlblStringToken[UNGET_STACK_SIZE][LINE_LEN_LONG],         /* Unget tokens.*/
  88.     GlblUnGetChar = 0,
  89.     *GlblFloatFormat = "%lg";
  90. static IPObjectStruct
  91.     *GlblAllSrfs = NULL,
  92.     *GlblAllCrvs = NULL,
  93.     *GlblAllObjs = NULL;
  94. static FILE
  95.     *IritPrsrOutputFile = NULL;
  96. static IritPrsrPrintFuncType
  97.     IritPrsrPrintFunc = NULL;
  98.  
  99. jmp_buf _IritPrsrLongJumpBuffer;           /* Used in error traping. */
  100. int _IritPrsrPolyListCirc = FALSE,
  101.     _IritPrsrReadSocket = FALSE,          /* If TRUE - read from socket. */
  102.     _IritPrsrWriteSocket = FALSE,           /* If TRUE - write to socket. */
  103.     _IritPrsrReadWriteBinary = FALSE, /* If TRUE - read/write data directly. */
  104.     IritPrsrWasViewMat = FALSE,
  105.     IritPrsrWasPrspMat = FALSE;
  106. MatrixType IritPrsrViewMat = {              /* Isometric view, by default. */
  107.     { -0.707107, -0.408248, 0.577350, 0.000000 },
  108.     {  0.707107, -0.408248, 0.577350, 0.000000 },
  109.     {  0.000000,  0.816496, 0.577350, 0.000000 },
  110.     {  0.000000,  0.000000, 0.000000, 1.000000 }
  111. };
  112. MatrixType IritPrsrPrspMat = {
  113.     { 1, 0, 0, 0 },
  114.     { 0, 1, 0, 0 },
  115.     { 0, 0, 1, -0.35 },
  116.     { 0, 0, 0, 1.0 }
  117. };
  118.  
  119. static void UnGetToken(char *StringToken);
  120. static int InputGetC(FILE *f);
  121. static int InputEOF(FILE *f);
  122. static int GetStringToken(FILE *f, char *StringToken, int *Quoted);
  123. static TokenType GetToken(FILE *f, char *StringToken);
  124. static void GetVertexAttributes(IPVertexStruct *PVertex, FILE *f);
  125. static void GetPolygonAttributes(IPPolygonStruct *PPolygon, FILE *f);
  126. static void GetObjectAttributes(IPObjectStruct *PObject, FILE *f);
  127. static void GetGenericAttribute(IPAttributeStruct **Attrs, FILE *f, char *Name);
  128. static void GetPointData(FILE *f, IPPolygonStruct *PPolygon, int IsPolygon);
  129.  
  130. static void FlattenTree(IPObjectStruct *PObj);
  131. static void IritPrsrGetAllObjects(FILE *f, IPObjectStruct *PObjParent,
  132.                                 int Level);
  133. static void GetCloseParenToken(FILE *f);
  134. static void SkipToCloseParenToken(FILE *f);
  135. static void GetNumericToken(FILE *f, RealType *r);
  136. static void IritPrsrGetAuxObject(FILE *f, IPObjectStruct *PObj);
  137.  
  138. static void IritPrsrPutAllObjects(IPObjectStruct *PObj, int Indent);
  139. static char *Real2Str(RealType R);
  140.  
  141. #ifdef USE_VARARGS
  142. static void IFprintf(int Indent, char *va_alist, ...);
  143. #else
  144. static void IFprintf(int Indent, char *Format, ...);
  145. #endif /* USE_VARARGS */
  146.  
  147. /*****************************************************************************
  148. * Open a data file for read/write.                         *
  149. *****************************************************************************/
  150. FILE *IritPrsrOpenDataFile(char *FileName, int Read, int Messages)
  151. {
  152.     FILE *f;
  153.     int i,
  154.     IsPipe = FALSE;
  155.     char *p;
  156.  
  157.     if (strstr(FileName, ".bdt") || strstr(FileName, ".BDT"))
  158.     _IritPrsrReadWriteBinary = TRUE;
  159.  
  160.     if (Read) {
  161.     if (strcmp(FileName, "-") == 0) {
  162.         f = stdin;
  163.     }
  164. #if defined(__UNIX__) || defined(OS2GCC)
  165.     else if ((p = strrchr(FileName, '.')) != NULL &&
  166.          strcmp(p, ".Z") == 0) {
  167.         char Cmd[LINE_LEN];
  168.  
  169.         sprintf(Cmd, "zcat %s", FileName);
  170.         f = popen(Cmd, "r");
  171.         IsPipe = TRUE;
  172.     }
  173. #endif /* __UNIX__ || OS2GCC */
  174.     else {
  175.         if ((f = fopen(FileName, "r")) == NULL) {
  176.         if (Messages)
  177.             fprintf(stderr, "Can't open data file %s.\n", FileName);
  178.         return NULL;
  179.         }
  180.     }
  181.     }
  182.     else { /* Write */
  183.     if (strcmp(FileName, "-") == 0) {
  184.         f = stdout;
  185.     }
  186. #if defined(__UNIX__) || defined(OS2GCC)
  187.     else if ((p = strrchr(FileName, '.')) != NULL &&
  188.          strcmp(p, ".Z") == 0) {
  189.         char Cmd[LINE_LEN];
  190.  
  191.         sprintf(Cmd, "compress > %s", FileName);
  192.         f = popen(Cmd, "w");
  193.         IsPipe = TRUE;
  194.     }
  195. #endif /* __UNIX__ || OS2GCC */
  196.     else {
  197.         if ((f = fopen(FileName, "w")) == NULL) {
  198.         if (Messages)
  199.             fprintf(stderr, "Can't open data file %s.\n", FileName);
  200.         return NULL;
  201.         }
  202.     }
  203.     }
  204.  
  205. #if defined(__OS2GCC__) || defined(__WINNT__)
  206.     if (_IritPrsrReadWriteBinary)
  207.     setmode(FileHandle, O_BINARY);    /* Make sure it is in binary mode. */
  208. #endif /* __OS2GCC__ || __WINNT__ */
  209.  
  210.     for (i = 0; i < MAX_NUM_OPEN_FILES; i++)
  211.     if (OpenedFiles[i].f == NULL) {
  212.         OpenedFiles[i].f = f;
  213.         OpenedFiles[i].IsPipe = IsPipe;
  214.         break;
  215.     }
  216.     if (Messages && i >= MAX_NUM_OPEN_FILES)
  217.     fprintf(stderr, "Opened file table is full.\n");
  218.  
  219.     return f;
  220. }
  221.  
  222. /*****************************************************************************
  223. * Close a data file for read/write.                         *
  224. *****************************************************************************/
  225. void IritPrsrCloseDataFile(FILE *f)
  226. {
  227. #ifdef __UNIX__
  228.     int i,
  229.     IsPipe = FALSE;
  230.  
  231.     for (i = 0; i < MAX_NUM_OPEN_FILES; i++)
  232.     if (OpenedFiles[i].f == f) {
  233.         IsPipe = OpenedFiles[i].IsPipe;
  234.         OpenedFiles[i].f = NULL;
  235.         break;
  236.     }
  237.   
  238.     if (IsPipe)
  239.     pclose(f);
  240.     else
  241. #endif /* __UNIX__ */
  242.     fclose(f);
  243.  
  244.     _IritPrsrReadWriteBinary = FALSE;
  245. }
  246.  
  247. /*****************************************************************************
  248. * Read data from an set of files specified by file names.             *
  249. * Messages and MoreMessages controls the level of printout to stderr.        *
  250. *****************************************************************************/
  251. IPObjectStruct *IritPrsrGetDataFiles(char **DataFileNames, int NumOfDataFiles,
  252.                      int Messages, int MoreMessages)
  253. {
  254.     int    i;
  255.     char *ErrorMsg;
  256.     FILE *f;
  257.     IPObjectStruct *PObj, *PObjTail,
  258.     *PObjHead = NULL;
  259.  
  260.     for    (i = 0; i < NumOfDataFiles; i++) {
  261.     if (MoreMessages)
  262.         fprintf(stderr, "Reading data file %s\n", *DataFileNames);
  263.  
  264.     if ((f = IritPrsrOpenDataFile(*DataFileNames, TRUE, Messages)) == NULL)
  265.         continue;
  266.  
  267.     if ((PObj = IritPrsrGetObjects(f)) != NULL) {  /* Get the data file. */
  268.         PObjTail = PObj;
  269.         while (PObjTail -> Pnext)
  270.         PObjTail = PObjTail -> Pnext;
  271.         PObjTail -> Pnext = PObjHead;
  272.         PObjHead = PObj;
  273.     }
  274.  
  275.     if (MoreMessages && IritPrsrParseError(&ErrorMsg))
  276.         fprintf(stderr, "File %s, %s\n", *DataFileNames, ErrorMsg);
  277.  
  278.     IritPrsrCloseDataFile(f);
  279.  
  280.     DataFileNames++;              /* Skip to next file name. */
  281.     }
  282.  
  283.     if (PObjHead == NULL) {
  284.     if (Messages)
  285.         fprintf(stderr, "No data found.\n");
  286.     return NULL;
  287.     }
  288.  
  289.     return PObjHead;
  290. }
  291.  
  292. /*****************************************************************************
  293. * Routine to read the data from    a given    file.                     *
  294. *   Returns NULL if EOF was reached or error occured.                 *
  295. *****************************************************************************/
  296. IPObjectStruct *IritPrsrGetObjects(FILE *f)
  297. {
  298.     IPObjectStruct *PObj;
  299.  
  300.     /* If the following gain control and is non zero - its from error! */
  301.     if (setjmp(_IritPrsrLongJumpBuffer) != 0)
  302.     return NULL;
  303.  
  304.     if (_IritPrsrReadWriteBinary)
  305.         PObj = IritPrsrGetBinObject(f);
  306.     else {
  307.     PObj = IPAllocObject("", IP_OBJ_UNDEF, NULL);
  308.     GlblToken = 0;             /* Used in UnGetToken token buffer. */
  309.     GlblParserError = IP_NO_ERR;                /* Reset errors. */
  310.     GlblLineCount = 1;                  /* Reset line counter. */
  311.  
  312.     IritPrsrGetAllObjects(f, PObj, 0);
  313.     if (IP_IS_UNDEF_OBJ(PObj)) {
  314.         IPFreeObject(PObj);
  315.         return NULL;
  316.     }
  317.     }
  318.  
  319.     return IritPrsrProcessReadObject(PObj);
  320. }
  321.  
  322. /*****************************************************************************
  323. * Process a read object, before returning it to the caller.             *
  324. *****************************************************************************/
  325. IPObjectStruct *IritPrsrProcessReadObject(IPObjectStruct *PObj)
  326. {
  327.     if (IP_IS_OLST_OBJ(PObj)) {
  328.         if (ListObjectGet(PObj, 0) == NULL) {
  329.         /* Nothing read in. */
  330.         IPFreeObject(PObj);
  331.         PObj = NULL;
  332.         IritPrsrParserAbort(IP_ERR_FILE_EMPTY, "");
  333.     }
  334.     else if (ListObjectGet(PObj, 1) == NULL) {
  335.         IPObjectStruct
  336.         *PTmp = ListObjectGet(PObj, 0);
  337.  
  338.         /* Only one object in list - return the object instead. */
  339.         ListObjectInsert(PObj, 0, NULL);
  340.         IPFreeObject(PObj);
  341.         PObj = PTmp;
  342.     }
  343.     }
  344.  
  345.     IritPrsrPropagateAttrs(PObj, NULL);
  346.  
  347.     if (GlblFlattenObjects) {
  348.     GlblAllSrfs = NULL;
  349.     GlblAllCrvs = NULL;
  350.     GlblAllObjs = NULL;
  351.  
  352.     FlattenTree(PObj);
  353.  
  354.     if (GlblAllCrvs != NULL || GlblAllSrfs != NULL) {
  355.         IPObjectStruct *PTmp, *PObjs;
  356.  
  357.         if ((PObjs = IritPrsrProcessFreeForm(GlblAllCrvs,
  358.                          GlblAllSrfs)) != NULL) {
  359.         for (PTmp = PObjs;
  360.              PTmp -> Pnext != NULL;
  361.              PTmp = PTmp -> Pnext) {
  362.             if (AttrGetObjectColor(PTmp) == IP_ATTR_NO_COLOR)
  363.                 AttrSetObjectColor(PTmp, IP_LOAD_COLOR);
  364.         }
  365.         PTmp -> Pnext = GlblAllObjs;
  366.         GlblAllObjs = PObjs;
  367.         }
  368.     }
  369.  
  370.     PObj = IritPrsrReverseObjList(GlblAllObjs);
  371.     }
  372.  
  373.     return PObj;
  374. }
  375.  
  376. /*****************************************************************************
  377. * Control the flattening of an object.                         *
  378. *****************************************************************************/
  379. void IritPrsrSetPolyListCirc(int Circ)
  380. {
  381.     _IritPrsrPolyListCirc = Circ;
  382. }
  383.  
  384. /*****************************************************************************
  385. * Control the flattening of an object.                         *
  386. *****************************************************************************/
  387. void IritPrsrSetFlattenObjects(int Flatten)
  388. {
  389.     GlblFlattenObjects = Flatten;
  390. }
  391.  
  392. /*****************************************************************************
  393. * Control the flattening of an object.                         *
  394. *****************************************************************************/
  395. void IritPrsrSetReadOneObject(int OneObject)
  396. {
  397.     GlblReadOneObject = OneObject;
  398. }
  399.  
  400. /*****************************************************************************
  401. * Propagate attributes from list objects down into their items.             *
  402. *****************************************************************************/
  403. void IritPrsrPropagateAttrs(IPObjectStruct *PObj, IPAttributeStruct *Attrs)
  404. {
  405.     IPAttributeStruct *Attr;
  406.  
  407.     if (IP_IS_OLST_OBJ(PObj)) {
  408.     int i;
  409.     IPObjectStruct *PTmp;
  410.  
  411.     /* Collect all attributes of this list (including inherited ones)    */
  412.     /* and propagate them down to the list items.                 */
  413.     if (Attrs != NULL)
  414.         Attrs = AttrCopyAttributes(Attrs);
  415.  
  416.     for (Attr = PObj -> Attrs; Attr != NULL; Attr = Attr -> Pnext) {
  417.         if (!AttrFindAttribute(Attrs, Attr -> Name)) {
  418.         IPAttributeStruct
  419.             *TmpAttr = AttrCopyOneAttribute(Attr);
  420.  
  421.         TmpAttr -> Pnext = Attrs;
  422.         Attrs = TmpAttr;
  423.         }
  424.     }
  425.  
  426.     for (i = 0; (PTmp = ListObjectGet(PObj, i)) != NULL; i++)
  427.         IritPrsrPropagateAttrs(PTmp, Attrs);
  428.  
  429.     AttrFreeAttributes(&Attrs);
  430.     }
  431.     else {
  432.     /* Regular object - add to its attribute list every attribute in     */
  433.     /* Attrs that is not found in its attribute list.             */
  434.     for (Attr = Attrs; Attr != NULL; Attr = Attr -> Pnext) {
  435.         if (!AttrFindAttribute(PObj -> Attrs, Attr -> Name)) {
  436.         IPAttributeStruct
  437.             *TmpAttr = AttrCopyOneAttribute(Attr);
  438.  
  439.         TmpAttr -> Pnext = PObj -> Attrs;
  440.         PObj -> Attrs = TmpAttr;
  441.         }
  442.     }
  443.     }
  444. }
  445.  
  446. /*****************************************************************************
  447. * Flatten a tree hierarchy of objects and push them onto the global list for *
  448. * curves surfaces and other objects.                         *
  449. *****************************************************************************/
  450. static void FlattenTree(IPObjectStruct *PObj)
  451. {
  452.     int i;
  453.     IPObjectStruct *PTmp;
  454.  
  455.     if (IP_IS_OLST_OBJ(PObj)) {
  456.     for (i = 0; (PTmp = ListObjectGet(PObj, i)) != NULL; i++)
  457.         FlattenTree(PTmp);
  458.  
  459.     ListObjectInsert(PObj, 0, NULL);
  460.     IPFreeObject(PObj);
  461.     }
  462.     else if (IP_IS_CRV_OBJ(PObj)) {
  463.     PObj -> Pnext = GlblAllCrvs;
  464.     GlblAllCrvs = PObj;
  465.     }
  466.     else if (IP_IS_SRF_OBJ(PObj)) {
  467.     PObj -> Pnext = GlblAllSrfs;
  468.     GlblAllSrfs = PObj;
  469.     }
  470.     else {
  471.     PObj -> Pnext = GlblAllObjs;
  472.     GlblAllObjs = PObj;
  473.     }
  474. }
  475.  
  476. /*****************************************************************************
  477. * Routine to read the geometry data from a given file. Reads "[OBJECT ..."   *
  478. * prefixes only and invoke the auxiliary routine.                 *
  479. * Note objects may be recursively defined.                     *
  480. *****************************************************************************/
  481. static void IritPrsrGetAllObjects(FILE *f, IPObjectStruct *PObjParent,
  482.                                 int Level)
  483. {
  484.     char StringToken[LINE_LEN_LONG];
  485.     TokenType Token;
  486.     int    i,
  487.     WasObjectToken = FALSE,
  488.     ObjCount = 0,
  489.     Quit = FALSE;
  490.     IPObjectStruct *PObj;
  491.  
  492.     while (!Quit) {
  493.         while ((Token = GetToken(f, StringToken)) != TOKEN_OPEN_PAREN &&
  494.            Token != TOKEN_CLOSE_PAREN &&
  495.            Token != TOKEN_EOF);
  496.  
  497.     if (Token == TOKEN_CLOSE_PAREN || Token == TOKEN_EOF) {
  498.         if (Token == TOKEN_CLOSE_PAREN)
  499.         UnGetToken(StringToken);
  500.         Quit = TRUE;
  501.         break;
  502.     }
  503.  
  504.     switch (GetToken(f, StringToken)) {
  505.         case TOKEN_OBJECT:
  506.         WasObjectToken = TRUE;
  507.  
  508.             ReallocNewTypeObject(PObjParent, IP_OBJ_LIST_OBJ);
  509.         PObj = IPAllocObject("", IP_OBJ_UNDEF, NULL);
  510.  
  511.         /* The following handle optional attributes in record. */
  512.         if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
  513.             GetObjectAttributes(PObj, f);
  514.         else {
  515.             UnGetToken(StringToken);
  516.         }
  517.  
  518.         if (AttrGetObjectColor(PObj) == IP_ATTR_NO_COLOR)
  519.             AttrSetObjectColor(PObj, IP_LOAD_COLOR);
  520.  
  521.         if (GetToken(f, StringToken) == TOKEN_OTHER &&
  522.             stricmp(StringToken, "NONE") != 0) {
  523.             for (i = 0; i < strlen(StringToken); i++)
  524.                 PObj -> Name[i] =
  525.                 islower(StringToken[i]) ? toupper(StringToken[i])
  526.                             : StringToken[i];
  527.             PObj -> Name[i] = 0;
  528.         }
  529.  
  530.         IritPrsrGetAllObjects(f, PObj, Level + 1);
  531.  
  532.         GetCloseParenToken(f);
  533.  
  534.         if (IP_IS_UNDEF_OBJ(PObj))
  535.             IritPrsrParserAbort(IP_ERR_OBJECT_EMPTY, "");
  536.  
  537.         ListObjectInsert(PObjParent, ObjCount++, PObj);
  538.         break;
  539.         default:
  540.         if (WasObjectToken) {
  541.             IritPrsrParserAbort(IP_ERR_OBJECT_EXPECTED, StringToken);
  542.         }
  543.         UnGetToken(StringToken);
  544.         UnGetToken("[");
  545.         IritPrsrGetAuxObject(f, PObjParent);
  546.         Quit = TRUE;
  547.         break;
  548.     }
  549.  
  550.     if (Level == 0 && WasObjectToken && GlblReadOneObject)
  551.         Quit = TRUE;
  552.     }
  553.  
  554.     if (IP_IS_OLST_OBJ(PObjParent)) {
  555.     ListObjectInsert(PObjParent, ObjCount++, NULL);
  556.     }
  557. }
  558.  
  559. /*****************************************************************************
  560. * Routine to get close paren token from f.                     *
  561. *****************************************************************************/
  562. static void GetCloseParenToken(FILE *f)
  563. {
  564.     char StringToken[LINE_LEN_LONG];
  565.  
  566.     if (GetToken(f, StringToken) != TOKEN_CLOSE_PAREN)
  567.     IritPrsrParserAbort(IP_ERR_CLOSE_PAREN_EXPECTED, StringToken);
  568. }
  569.  
  570. /*****************************************************************************
  571. * Routine to get close paren token from f.                     *
  572. *****************************************************************************/
  573. static void SkipToCloseParenToken(FILE *f)
  574. {
  575.     char StringToken[LINE_LEN_LONG];
  576.  
  577.     while (!InputEOF(f) && GetToken(f, StringToken) != TOKEN_CLOSE_PAREN);
  578. }
  579.  
  580. /*****************************************************************************
  581. * Routine to get one numeric token into r.                     *
  582. *****************************************************************************/
  583. static void GetNumericToken(FILE *f, RealType *r)
  584. {
  585.     char StringToken[LINE_LEN_LONG];
  586.  
  587.     GetToken(f, StringToken);
  588. #   ifdef DOUBLE
  589.     if (sscanf(StringToken, "%lf", r) != 1)
  590. #   else
  591.     if (sscanf(StringToken, "%f", r) != 1)
  592. #   endif /* DOUBLE */
  593.         IritPrsrParserAbort(IP_ERR_NUMBER_EXPECTED, StringToken);
  594. }
  595.  
  596. /*****************************************************************************
  597. * Routine to read the content of a single object. Return TRUE if data is     *
  598. * useful for this parser, FALSE if data should be purged.             *
  599. *****************************************************************************/
  600. static void IritPrsrGetAuxObject(FILE *f, IPObjectStruct *PObj)
  601. {
  602.     int    i, j, ErrLine;
  603.     TokenType
  604.     Token = TOKEN_NONE;
  605.     char *ErrStr, StringToken[LINE_LEN_LONG];
  606.     CagdRType *Coords;
  607.     IPPolygonStruct *PPolygon;
  608.     CagdCrvStruct *PCurve;
  609.     CagdSrfStruct *PSurface;
  610.  
  611.     ReallocNewTypeObject(PObj, IP_OBJ_UNDEF);
  612.  
  613.     while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN) {
  614.     switch (Token = GetToken(f, StringToken)) {
  615.         case TOKEN_POLYGON:
  616.         case TOKEN_POLYLINE:
  617.         case TOKEN_POINTLIST:
  618.         ReallocNewTypeObject(PObj, IP_OBJ_POLY);
  619.         PPolygon = IPAllocPolygon(0, 0, NULL, NULL);
  620.         switch (Token) {
  621.             case TOKEN_POLYGON:
  622.             IP_SET_POLYGON_OBJ(PObj);
  623.             break;
  624.             case TOKEN_POLYLINE:
  625.             IP_SET_POLYLINE_OBJ(PObj);
  626.             break;
  627.             case TOKEN_POINTLIST:
  628.             IP_SET_POINTLIST_OBJ(PObj);
  629.             break;
  630.             default:
  631.             IritPrsrParserAbort(IP_ERR_UNDEF_EXPR_HEADER,
  632.                         StringToken);
  633.             break;
  634.         }
  635.  
  636.         /* The following handle the optional attributes in struct.   */
  637.         if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
  638.             GetPolygonAttributes(PPolygon, f);
  639.         else
  640.             UnGetToken(StringToken);
  641.  
  642.         /* The following handles reading the vertices. */
  643.         GetPointData(f, PPolygon, IP_IS_POLYGON_OBJ(PObj));
  644.  
  645.         if (IP_IS_POLYGON_OBJ(PObj)) {
  646.             if (!IP_HAS_PLANE_POLY(PPolygon))
  647.             IritPrsrUpdatePolyPlane(PPolygon);
  648.  
  649.             IritPrsrUpdateVrtxNrml(PPolygon, PPolygon -> Plane);
  650.         }
  651.  
  652.         PPolygon -> Pnext = PObj -> U.Pl;
  653.         PObj -> U.Pl = PPolygon;
  654.         break;
  655.         case TOKEN_SURFACE:
  656.         ReallocNewTypeObject(PObj, IP_OBJ_SURFACE);
  657.         ErrLine = GlblLineCount;
  658.         PSurface = CagdSrfReadFromFile2(f, &ErrStr, &ErrLine);
  659.         GlblLineCount = ErrLine;
  660.  
  661.         if (ErrStr != NULL) {
  662.             IritPrsrParserAbort(IP_ERR_CAGD_LIB_ERR, ErrStr);
  663.             break;
  664.         }
  665.  
  666.         if (PSurface != NULL) {
  667.             PSurface -> Pnext = PObj -> U.Srfs;
  668.             PObj -> U.Srfs = PSurface;
  669.         }
  670.         break;
  671.         case TOKEN_CURVE:
  672.         ReallocNewTypeObject(PObj, IP_OBJ_CURVE);
  673.         ErrLine = GlblLineCount;
  674.         PCurve = CagdCrvReadFromFile2(f, &ErrStr, &ErrLine);
  675.         GlblLineCount = ErrLine;
  676.  
  677.         if (ErrStr != NULL) {
  678.             IritPrsrParserAbort(IP_ERR_CAGD_LIB_ERR, ErrStr);
  679.             break;
  680.         }
  681.  
  682.         if (PCurve != NULL) {
  683.             PCurve -> Pnext = PObj -> U.Crvs;
  684.             PObj -> U.Crvs = PCurve;
  685.         }
  686.         break;
  687.         case TOKEN_NUMBER:
  688.         ReallocNewTypeObject(PObj, IP_OBJ_NUMERIC);
  689.         GetNumericToken(f, &PObj -> U.R);
  690.         GetCloseParenToken(f);
  691.         break;
  692.         case TOKEN_STRING:
  693.         ReallocNewTypeObject(PObj, IP_OBJ_STRING);
  694.         GetToken(f, PObj -> U.Str);
  695.         GetCloseParenToken(f);
  696.         break;
  697.         case TOKEN_POINT:
  698.         ReallocNewTypeObject(PObj, IP_OBJ_POINT);
  699.         for (i = 0; i < 3; i++)
  700.             GetNumericToken(f, &PObj -> U.Pt[i]);
  701.         GetCloseParenToken(f);
  702.         break;
  703.         case TOKEN_VECTOR:
  704.         ReallocNewTypeObject(PObj, IP_OBJ_VECTOR);
  705.         for (i = 0; i < 3; i++)
  706.             GetNumericToken(f, &PObj -> U.Vec[i]);
  707.         GetCloseParenToken(f);
  708.         break;
  709.         case TOKEN_PLANE:
  710.         ReallocNewTypeObject(PObj, IP_OBJ_PLANE);
  711.         for (i = 0; i < 4; i++)
  712.             GetNumericToken(f, &PObj -> U.Plane[i]);
  713.         GetCloseParenToken(f);
  714.         break;
  715.         case TOKEN_MATRIX:
  716.         ReallocNewTypeObject(PObj, IP_OBJ_MATRIX);
  717.         for (i = 0; i < 4; i++)
  718.             for (j = 0; j < 4; j++)
  719.             GetNumericToken(f, &(*PObj -> U.Mat)[i][j]);
  720.         GetCloseParenToken(f);
  721.  
  722.         if (stricmp(PObj -> Name, "VIEW_MAT") == 0) {
  723.             IritPrsrWasViewMat = TRUE;
  724.             MAT_COPY(IritPrsrViewMat, PObj -> U.Mat);
  725.         }
  726.         else if (stricmp(PObj -> Name, "PRSP_MAT") == 0) {
  727.             IritPrsrWasPrspMat = TRUE;
  728.             MAT_COPY(IritPrsrPrspMat, PObj -> U.Mat);
  729.         }
  730.         break;
  731.         case TOKEN_CTLPT:
  732.         ReallocNewTypeObject(PObj, IP_OBJ_CTLPT);
  733.         GetToken(f, StringToken);
  734.  
  735.         i = atoi(&StringToken[1]);
  736.         if ((StringToken[0] == 'P' || StringToken[0] == 'E' ) &&
  737.             i > 0 && i < 6) {
  738.            j = StringToken[0] == 'E';
  739.            PObj -> U.CtlPt.PtType = CAGD_MAKE_PT_TYPE(!j, i);
  740.         }
  741.         else {
  742.             IritPrsrParserAbort(IP_ERR_PT_TYPE_EXPECTED, StringToken);
  743.             i = j = 0;
  744.             break;
  745.         }
  746.  
  747.         Coords = PObj -> U.CtlPt.Coords;
  748.         for ( i += 1 - j; i > 0; i--)
  749.             GetNumericToken(f, &Coords[j++]);
  750.         GetCloseParenToken(f);
  751.         break;
  752.         default:
  753.         IritPrsrParserAbort(IP_ERR_UNDEF_EXPR_HEADER, StringToken);
  754.         break;
  755.     } /* Of switch. */
  756.     } /* Of while. */
  757.  
  758.     UnGetToken(StringToken);
  759. }
  760.  
  761. /*****************************************************************************
  762. *   Routine to unget one token (on stack of UNGET_STACK_SIZE levels!)         *
  763. *****************************************************************************/
  764. static void UnGetToken(char *StringToken)
  765. {
  766.     if (GlblToken >= UNGET_STACK_SIZE)
  767.      IritPrsrParserAbort(IP_ERR_STACK_OVERFLOW, "");
  768.  
  769.     strcpy(GlblStringToken[GlblToken], StringToken);
  770.     GlblToken++;  /* GlblToken exists - Something in it (no overflow check). */
  771. }
  772.  
  773. /*****************************************************************************
  774. *   Routine to unget a single character from input stream.             *
  775. *****************************************************************************/
  776. void IritPrsrInputUnGetC(char c)
  777. {
  778.     GlblUnGetChar = c;
  779. }
  780.  
  781. /*****************************************************************************
  782. *   Routine to get a single character from input stream.             *
  783. * If input returns EOF wait until new inputs arrive (can happen if reading   *
  784. * from a non io blocked socket).                         *
  785. *****************************************************************************/
  786. static int InputGetC(FILE *f)
  787. {
  788.     int c;
  789.  
  790.     if (GlblUnGetChar) {
  791.     c = GlblUnGetChar;
  792.  
  793.     GlblUnGetChar = 0;
  794.     }
  795.     else if (_IritPrsrReadSocket) {
  796.     while ((c = SocClientReadCharNonBlock()) == EOF)
  797.         IritSleep(10);
  798.     }
  799.     else
  800.     c = getc(f);
  801.  
  802.     return c;
  803. }
  804.  
  805. /*****************************************************************************
  806. *   Routine to test for EOF condition in input stream.                 *
  807. *****************************************************************************/
  808. static int InputEOF(FILE *f)
  809. {
  810.     if (_IritPrsrReadSocket)
  811.     return FALSE;
  812.     else
  813.     return feof(f);
  814. }
  815.  
  816. /*****************************************************************************
  817. *   Routine to request the parser to read from a socket instead of a file.   *
  818. *****************************************************************************/
  819. void IritPrsrReadSocket(int ReadSocket)
  820. {
  821.     _IritPrsrReadSocket = ReadSocket;
  822.     CagdReadSocket(ReadSocket);
  823. }
  824.  
  825. /*****************************************************************************
  826. *   Routine to request the parser to read from a socket instead of a file.   *
  827. *****************************************************************************/
  828. void IritPrsrWriteSocket(int WriteSocket)
  829. {
  830.     _IritPrsrWriteSocket = WriteSocket;
  831.     CagdWriteSocket(WriteSocket);
  832. }
  833.  
  834. /*****************************************************************************
  835. *   Routine to get the next token out of the input file    f.             *
  836. * Returns TRUE if !InputEOF and the next token found in StringToken.         *
  837. * Note:    StringToken must be allocated before calling this routine!         *
  838. *****************************************************************************/
  839. static int GetStringToken(FILE *f, char *StringToken, int *Quoted)
  840. {
  841.     int    len;
  842.     char *LocalStringToken,
  843.     c = EOF;
  844.  
  845.     *Quoted = FALSE;
  846.  
  847.     if (GlblToken) { /*    get first the unget token */
  848.     GlblToken--;
  849.     strcpy(StringToken, GlblStringToken[GlblToken]);
  850.     return TRUE;
  851.     }
  852.     /* skip white spaces: */
  853.     while ((!InputEOF(f)) &&
  854.        (((c = InputGetC(f)) == ' ') || (c == '\t') || (c == '\n')) &&
  855.        (c != (char) EOF))
  856.     if (c == '\n')
  857.         GlblLineCount++;                 /* Count the lines. */
  858.  
  859.     LocalStringToken = StringToken;
  860.     if (c == '[')              /* Its a token by    itself so return it. */
  861.     *LocalStringToken++ = c;          /* Copy the token    into string. */
  862.     else {
  863.     if (!InputEOF(f) && (c != (char) EOF)) {
  864.         if (c == '"') {
  865.         *Quoted = TRUE;
  866.         c = InputGetC(f);
  867.         do {
  868.             *LocalStringToken++ = c;      /* Copy the quoted string. */
  869.             if (c == '\\') {
  870.             /* Next character is quoted - copy verbatim. */
  871.             *--LocalStringToken = c = InputGetC(f);
  872.             LocalStringToken++;
  873.             }
  874.         }
  875.         while ((!InputEOF(f)) &&
  876.                ((c = InputGetC(f)) != '"') &&
  877.                (c != '\n') &&
  878.                (c != (char) EOF));
  879.         }
  880.         else {
  881.         do
  882.             *LocalStringToken++ = c;  /* Copy the token into string. */
  883.         while ((!InputEOF(f)) &&
  884.                ((c = InputGetC(f)) != ' ') &&
  885.                (c != '\t') &&
  886.                (c != '\n') &&
  887.                (c != (char) EOF));
  888.         }
  889.         if (!InputEOF(f) && c == '\n')
  890.             IritPrsrInputUnGetC(c);     /* Save it to be counted next time. */
  891.     }
  892.     }
  893.     *LocalStringToken =    0;                     /* Put    eos. */
  894.  
  895.     /* The following handles the spacial case were we have XXXX] - we must   */
  896.     /* split it    into two token XXXX and    ], UnGetToken(']') and return XXXX:  */
  897.     if ((StringToken[len = strlen(StringToken) - 1] == ']') && (len > 0)) {
  898.     /* Return CloseParan */
  899.     UnGetToken(&StringToken[len]);             /* Save next token. */
  900.     StringToken[len] = 0;            /* Set end of string on    "]". */
  901.     }
  902.  
  903.     return !InputEOF(f) && (c != (char) EOF);
  904. }
  905.  
  906. /*****************************************************************************
  907. *   Routine to get the next token out of the input file    f as token number.   *
  908. * Note:    StringToken must be allocated before calling this routine!         *
  909. *****************************************************************************/
  910. static TokenType GetToken(FILE *f, char *StringToken)
  911. {
  912.     static int IntTokens[] = {
  913.     TOKEN_OPEN_PAREN,
  914.     TOKEN_CLOSE_PAREN,
  915.     TOKEN_VERTEX,
  916.     TOKEN_POLYGON,
  917.     TOKEN_POLYLINE,
  918.     TOKEN_POINTLIST,
  919.     TOKEN_OBJECT,
  920.     TOKEN_COLOR,
  921.     TOKEN_RGB,
  922.     TOKEN_INTERNAL,
  923.     TOKEN_NORMAL,
  924.     TOKEN_PLANE,
  925.     TOKEN_CURVE,
  926.     TOKEN_SURFACE,
  927.     TOKEN_E1,
  928.     TOKEN_P1,
  929.     TOKEN_E2,
  930.     TOKEN_P2,
  931.     TOKEN_E3,
  932.     TOKEN_P3,
  933.     TOKEN_E4,
  934.     TOKEN_P4,
  935.     TOKEN_E5,
  936.     TOKEN_P5,
  937.     TOKEN_NUMBER,
  938.     TOKEN_STRING,
  939.     TOKEN_VECTOR,
  940.     TOKEN_POINT,
  941.     TOKEN_MATRIX,
  942.     TOKEN_CTLPT,
  943.     0
  944.     };
  945.     static char *StrTokens[] = {
  946.     "[",
  947.     "]",
  948.     "VERTEX",
  949.     "POLYGON",
  950.     "POLYLINE",
  951.     "POINTLIST",
  952.     "OBJECT",
  953.     "COLOR",
  954.     "RGB",
  955.     "INTERNAL",
  956.     "NORMAL",
  957.     "PLANE",
  958.     "CURVE",
  959.     "SURFACE",
  960.     "E1",
  961.     "P1",
  962.     "E2",
  963.     "P2",
  964.     "E3",
  965.     "P3",
  966.     "E4",
  967.     "P4",
  968.     "E5",
  969.     "P5",
  970.     "NUMBER",
  971.     "STRING",
  972.     "VECTOR",
  973.     "POINT",
  974.     "MATRIX",
  975.     "CTLPT",
  976.     NULL
  977.     };
  978.     int i, Quoted;
  979.  
  980.     if (!GetStringToken(f, StringToken, &Quoted))
  981.     return TOKEN_EOF;
  982.  
  983.     if (Quoted)
  984.     return TOKEN_QUOTED;
  985.  
  986.     for (i = 0; StrTokens[i] != NULL; i++)
  987.     if (stricmp(StringToken, StrTokens[i]) == 0)
  988.         return IntTokens[i];
  989.  
  990.     return TOKEN_OTHER;                  /* Must be number or name. */
  991. }
  992.  
  993. /*****************************************************************************
  994. * Routine to read from input file f the    following [ATTR ...] [ATTR ...].     *
  995. * Note the '[' was allready read.                         *
  996. *****************************************************************************/
  997. static void GetVertexAttributes(IPVertexStruct *PVertex, FILE *f)
  998. {
  999.     int i;
  1000.     RealType Len;
  1001.     char StringToken[LINE_LEN_LONG];
  1002.  
  1003.     do {
  1004.     switch (GetToken(f, StringToken)) {
  1005.         case TOKEN_INTERNAL:
  1006.         GetCloseParenToken(f);
  1007.         IP_SET_INTERNAL_VRTX(PVertex);
  1008.         break;
  1009.         case TOKEN_NORMAL:
  1010.         /* The following handles reading 3 coord. of vertex normal. */
  1011.         for (i = 0; i < 3; i++)
  1012.             GetNumericToken(f, &PVertex -> Normal[i]);
  1013.  
  1014.         /* Make sure it is normalized. */
  1015.         Len = PT_LENGTH(PVertex -> Normal);
  1016.         if (Len > 0) {
  1017.             for (i = 0; i < 3; i++)
  1018.             PVertex -> Normal[i] /= Len;
  1019.             IP_SET_NORMAL_VRTX(PVertex);
  1020.         }
  1021.         GetCloseParenToken(f);
  1022.         break;
  1023.         default:
  1024.         GetGenericAttribute(&PVertex -> Attrs, f, StringToken);
  1025.         break;
  1026.     }
  1027.     }
  1028.     while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
  1029.  
  1030.     UnGetToken(StringToken);
  1031. }
  1032.  
  1033. /*****************************************************************************
  1034. * Routine to read from input file f the    following [ATTR ...] [ATTR ...].     *
  1035. * Note the '[' was allready read.                         *
  1036. *****************************************************************************/
  1037. static void GetPolygonAttributes(IPPolygonStruct *PPolygon, FILE *f)
  1038. {
  1039.     int i;
  1040.     RealType Len;
  1041.     char StringToken[LINE_LEN_LONG];
  1042.  
  1043.     do {
  1044.     switch (GetToken(f, StringToken)) {
  1045.         case TOKEN_PLANE:
  1046.         /* The following handles reading of 4 coord. of plane eqn.. */
  1047.         for (i = 0; i < 4; i++)
  1048.             GetNumericToken(f, &PPolygon -> Plane[i]);
  1049.  
  1050.         /* Make sure it is normalized. */
  1051.         Len = PT_LENGTH(PPolygon -> Plane);
  1052.         if (Len > 0)
  1053.             for (i = 0; i < 4; i++)
  1054.             PPolygon -> Plane[i] /= Len;
  1055.         else
  1056.             IritPrsrParserAbort(IP_ERR_DEGEN_NORMAL, "");
  1057.  
  1058.         GetCloseParenToken(f);
  1059.         IP_SET_PLANE_POLY(PPolygon);
  1060.         break;
  1061.         default:
  1062.         GetGenericAttribute(&PPolygon -> Attrs, f, StringToken);
  1063.         break;
  1064.     }
  1065.     }
  1066.     while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
  1067.  
  1068.     UnGetToken(StringToken);
  1069. }
  1070.  
  1071. /*****************************************************************************
  1072. * Routine to read from input file f the    following [ATTR ...] [ATTR ...].     *
  1073. * Note the '[' was allready read.                         *
  1074. *****************************************************************************/
  1075. static void GetObjectAttributes(IPObjectStruct *PObject, FILE *f)
  1076. {
  1077.     int    i;
  1078.     char StringToken[LINE_LEN_LONG];
  1079.  
  1080.     do {
  1081.     switch (GetToken(f, StringToken)) {
  1082.         case TOKEN_COLOR:
  1083.         GetToken(f, StringToken);
  1084.         if (sscanf(StringToken, "%d", &i) != 1)
  1085.             IritPrsrParserAbort(IP_ERR_NUMBER_EXPECTED, StringToken);
  1086.         GetCloseParenToken(f);
  1087.         AttrSetObjectColor(PObject, i);
  1088.         break;
  1089.         default:
  1090.         GetGenericAttribute(&PObject -> Attrs, f, StringToken);
  1091.         break;
  1092.     }
  1093.     }
  1094.     while (GetToken(f, StringToken) == TOKEN_OPEN_PAREN);
  1095.  
  1096.     if (AttrGetObjectColor(PObject) == IP_ATTR_NO_COLOR)
  1097.         AttrSetObjectColor(PObject, IP_LOAD_COLOR);
  1098.  
  1099.     UnGetToken(StringToken);
  1100. }
  1101.  
  1102. /*****************************************************************************
  1103. * Routine to read one generic attribute.                     *
  1104. *****************************************************************************/
  1105. static void GetGenericAttribute(IPAttributeStruct **Attrs, FILE *f, char *Name)
  1106. {
  1107.     int Token;
  1108.     char StringToken[LINE_LEN_LONG];
  1109.  
  1110.     if ((Token = GetToken(f, StringToken)) == TOKEN_CLOSE_PAREN) {
  1111.     AttrSetStrAttrib(Attrs, Name, "");
  1112.     }
  1113.     else if (Token == TOKEN_QUOTED) {
  1114.     AttrSetStrAttrib(Attrs, Name, StringToken);
  1115.  
  1116.     SkipToCloseParenToken(f);
  1117.     }
  1118.     else {
  1119.     int i;
  1120.     double d;
  1121.  
  1122.     for (i = strlen(StringToken) - 1; i >= 0; i--) {
  1123.         if (!(isdigit(StringToken[i]) ||
  1124.           StringToken[i] == 'e' ||
  1125.           StringToken[i] == 'E' ||
  1126.           StringToken[i] == '.' ||
  1127.           StringToken[i] == '+' ||
  1128.           StringToken[i] == '-'))
  1129.         break;
  1130.     }
  1131.     if (i < 0 && sscanf(StringToken, "%lf", &d) == 1) {
  1132.         if (d == (int) d)
  1133.         AttrSetIntAttrib(Attrs, Name, (int) d);
  1134.         else
  1135.         AttrSetRealAttrib(Attrs, Name, d);
  1136.     }
  1137.     else
  1138.         AttrSetStrAttrib(Attrs, Name, StringToken);
  1139.  
  1140.     SkipToCloseParenToken(f);
  1141.     }
  1142. }
  1143.  
  1144. /*****************************************************************************
  1145. * Routine to read poly* vertex information.                     *
  1146. *****************************************************************************/
  1147. static void GetPointData(FILE *f, IPPolygonStruct *PPolygon, int IsPolygon)
  1148. {
  1149.     int i, j, Length;
  1150.     char StringToken[LINE_LEN_LONG];
  1151.     IPVertexStruct *V,
  1152.     *VTail = NULL;
  1153.  
  1154.     if (GetToken(f, StringToken) != TOKEN_OTHER ||
  1155.     sscanf(StringToken, "%d", &Length) != 1)
  1156.     IritPrsrParserAbort(IP_ERR_NUMBER_EXPECTED, StringToken);
  1157.  
  1158.     for (i = 0; i < Length; i++) {
  1159.     if (GetToken(f, StringToken) != TOKEN_OPEN_PAREN)
  1160.         IritPrsrParserAbort(IP_ERR_OPEN_PAREN_EXPECTED, StringToken);
  1161.  
  1162.     V = IPAllocVertex(0, 0, NULL, NULL);
  1163.  
  1164.     /* The following handle the optional attributes in struct. */
  1165.     if (GetToken(f, StringToken) == TOKEN_OPEN_PAREN)
  1166.         GetVertexAttributes(V, f);
  1167.     else
  1168.         UnGetToken(StringToken);
  1169.  
  1170.     for (j = 0; j < 3; j++)                /* Read coordinates. */
  1171.         GetNumericToken(f, &V -> Coord[j]);
  1172.  
  1173.     GetCloseParenToken(f);
  1174.  
  1175.     if (VTail == NULL)
  1176.         PPolygon -> PVertex = VTail = V;
  1177.     else {
  1178.         VTail -> Pnext = V;
  1179.         VTail = V;
  1180.     }
  1181.     }
  1182.  
  1183.     if (_IritPrsrPolyListCirc && IsPolygon)
  1184.     VTail -> Pnext = PPolygon -> PVertex;
  1185.  
  1186.     GetCloseParenToken(f);
  1187. }
  1188.  
  1189. /*****************************************************************************
  1190. *   Routine to update the Plane equation of the given polygon by the order   *
  1191. * of the first 3 vertices of that polygon.                     *
  1192. *****************************************************************************/
  1193. void IritPrsrUpdatePolyPlane(IPPolygonStruct *PPoly)
  1194. {
  1195.     int i;
  1196.     RealType Len, V1[3], V2[3],
  1197.     MaxLen = SQR(EPSILON);
  1198.     IPVertexStruct
  1199.     *VLast = NULL,
  1200.     *V = PPoly -> PVertex;
  1201.     PlaneType Plane;
  1202.  
  1203.     if (V == NULL || V -> Pnext == NULL || V -> Pnext -> Pnext == NULL)
  1204.     IritPrsrParserAbort(IP_ERR_DEGEN_POLYGON, "");
  1205.  
  1206.     for (i = 0; i < 4; i++)
  1207.     PPoly -> Plane[i] = 0.0;
  1208.  
  1209.     /* Force list to be circular. Will be recovered immediately after. */
  1210.     if (!_IritPrsrPolyListCirc) {
  1211.     VLast = IritPrsrGetLastVrtx(V);
  1212.     VLast -> Pnext = V;
  1213.     }
  1214.  
  1215.     do {
  1216.     PT_SUB(V1, V -> Coord, V -> Pnext -> Coord);
  1217.     V = V -> Pnext;
  1218.     PT_SUB(V2, V -> Coord, V -> Pnext -> Coord);
  1219.  
  1220.     Plane[0] = V1[1] * V2[2] - V2[1] * V1[2];
  1221.     Plane[1] = V1[2] * V2[0] - V2[2] * V1[0];
  1222.     Plane[2] = V1[0] * V2[1] - V2[0] * V1[1];
  1223.  
  1224.     /* Normalize the plane such that the normal has length of 1: */
  1225.     Len = PT_LENGTH(Plane);
  1226.     if (Len > MaxLen) {
  1227.         for (i = 0; i < 3; i++)
  1228.         PPoly -> Plane[i] = Plane[i] / Len;
  1229.  
  1230.         MaxLen = Len;
  1231.  
  1232.         if (MaxLen > SQR(NORMAL_MIN_VALID_LEN))
  1233.             break;
  1234.     }
  1235.  
  1236.     V = V -> Pnext;
  1237.     }
  1238.     while (V != PPoly -> PVertex &&
  1239.        V -> Pnext != NULL &&
  1240.        V -> Pnext -> Pnext != NULL);
  1241.  
  1242.     if (VLast != NULL) /* Recover non circular list, if was non circular. */
  1243.     VLast -> Pnext = NULL;
  1244.  
  1245.     if (MaxLen < SQR(EPSILON))
  1246.     IritPrsrParserAbort(IP_ERR_DEGEN_NORMAL, "");
  1247.  
  1248.     PPoly -> Plane[3] =
  1249.     -DOT_PROD(PPoly -> Plane, PPoly -> PVertex -> Coord);
  1250.  
  1251.     IP_SET_PLANE_POLY(PPoly);
  1252. }
  1253.  
  1254. /*****************************************************************************
  1255. *   Routine to update the Plane equation of the given polygon such that the  *
  1256. * Vin vertex will be in the positive side of it.                 *
  1257. *   It is assumed the polygon has at list 3 points...                 *
  1258. *****************************************************************************/
  1259. void IritPrsrUpdatePolyPlane2(IPPolygonStruct *PPoly, VectorType Vin)
  1260. {
  1261.     int i;
  1262.  
  1263.     IritPrsrUpdatePolyPlane(PPoly);
  1264.  
  1265.     if (DOT_PROD(PPoly -> Plane, Vin) + PPoly -> Plane[3] < 0) {
  1266.     /* Flip plane normal and reverse the vertex list. */
  1267.     IritPrsrReverseVrtxList(PPoly);
  1268.     for (i = 0; i < 4; i++)
  1269.         PPoly -> Plane[i] = (-PPoly -> Plane[i]);
  1270.     }
  1271. }
  1272.  
  1273. /*****************************************************************************
  1274. *   Routine to update all vertices in polygon to hold a default normal if    *
  1275. * have none already.                                 *
  1276. *****************************************************************************/
  1277. void IritPrsrUpdateVrtxNrml(IPPolygonStruct *PPoly, VectorType DefNrml)
  1278. {
  1279.     IPVertexStruct
  1280.     *V = PPoly -> PVertex;
  1281.  
  1282.     do {
  1283.     if (!IP_HAS_NORMAL_VRTX(V)) {
  1284.         PT_COPY(V -> Normal, DefNrml);
  1285.         IP_SET_NORMAL_VRTX(V);
  1286.     }
  1287.     V = V -> Pnext;
  1288.     }
  1289.     while (V != NULL && V != PPoly -> PVertex);
  1290. }
  1291.  
  1292. /*****************************************************************************
  1293. *   Reverse a list of objects.                             *
  1294. *****************************************************************************/
  1295. IPObjectStruct *IritPrsrReverseObjList(IPObjectStruct *PObj)
  1296. {
  1297.     IPObjectStruct
  1298.     *NewPObjs = NULL;
  1299.  
  1300.     while (PObj) {
  1301.     IPObjectStruct
  1302.         *Pnext = PObj -> Pnext;
  1303.  
  1304.     PObj -> Pnext = NewPObjs;
  1305.     NewPObjs = PObj;
  1306.  
  1307.     PObj = Pnext;
  1308.     }
  1309.  
  1310.     return NewPObjs;
  1311. }
  1312.  
  1313. /*****************************************************************************
  1314. *   Reverse the vertex list of a given polygon. This is used mainly to       *
  1315. * reverse polygons such that cross product of consecutive edges which form   *
  1316. * a convex corner will point in the polygon normal direction.             *
  1317. *****************************************************************************/
  1318. void IritPrsrReverseVrtxList(IPPolygonStruct *Pl)
  1319. {
  1320.     ByteType Tags, Count;
  1321.     IPVertexStruct *VNextNext, *VLast,
  1322.     *V = Pl -> PVertex,
  1323.     *VNext = V -> Pnext;
  1324.  
  1325.     /* Force list to be circular. Will be recovered immediately after. */
  1326.     if (!_IritPrsrPolyListCirc) {
  1327.     VLast = IritPrsrGetLastVrtx(V);
  1328.     VLast -> Pnext = V;
  1329.     }
  1330.  
  1331.     do {
  1332.     VNextNext = VNext -> Pnext;
  1333.     VNext -> Pnext = V;                 /* Reverse the pointer! */
  1334.  
  1335.     V = VNext;               /* Advance all 3 pointers by one. */
  1336.     VNext = VNextNext;
  1337.     VNextNext = VNextNext -> Pnext;
  1338.     }
  1339.     while (V != Pl -> PVertex);
  1340.  
  1341.     V = Pl -> PVertex;      /* Move the Tags/Count by one - to the right edge. */
  1342.     Tags = V -> Tags;
  1343.     Count = V -> Count;
  1344.     do {
  1345.     if (V -> Pnext == Pl -> PVertex) {
  1346.         V -> Tags = Tags;
  1347.         V -> Count = Count;
  1348.     }
  1349.     else {
  1350.         V -> Tags = V -> Pnext -> Tags;
  1351.         V -> Count = V -> Pnext -> Count;
  1352.     }
  1353.  
  1354.     V = V -> Pnext;
  1355.     }
  1356.     while (V != Pl -> PVertex);
  1357.  
  1358.     /* Recover non circular list, if needs to. */
  1359.     if (!_IritPrsrPolyListCirc) {
  1360.     VLast = IritPrsrGetLastVrtx(Pl -> PVertex);
  1361.     VLast -> Pnext = NULL;
  1362.     }
  1363. }
  1364.  
  1365. /*****************************************************************************
  1366. * Routine to abort parsing operation and save error reported.             *
  1367. *****************************************************************************/
  1368. void IritPrsrParserAbort(IritPrsrErrType ErrNum, char *Msg)
  1369. {
  1370.     GlblLineCount = GlblLineCount;
  1371.     GlblParserError = ErrNum;
  1372.     strcpy(GlblTokenError, Msg);    /* Keep the message in safe place... */
  1373.  
  1374.     longjmp(_IritPrsrLongJumpBuffer, 1);               /* Jump to... */
  1375. }
  1376.  
  1377. /*****************************************************************************
  1378. * Returns TRUE if error happened, FALSE otherwise.                 *
  1379. *   If error, then ErrorMsg is updated to point on static str describing it. *
  1380. *****************************************************************************/
  1381. int IritPrsrParseError(char **ErrorMsg)
  1382. {
  1383.     IritPrsrErrType Temp;
  1384.     char TempCopy[LINE_LEN_LONG];
  1385.  
  1386.     if ((Temp = GlblParserError) == IP_NO_ERR)
  1387.     return FALSE;
  1388.  
  1389.     strcpy(TempCopy, GlblTokenError);
  1390.     GlblParserError = IP_NO_ERR;
  1391.  
  1392.     switch (Temp) {
  1393.     case IP_ERR_NUMBER_EXPECTED:
  1394.         sprintf(GlblTokenError, "Line %d: Numeric data expected - found %s",
  1395.             GlblLineCount, TempCopy);
  1396.         break;
  1397.     case IP_ERR_OPEN_PAREN_EXPECTED:
  1398.         sprintf(GlblTokenError, "Line %d: '[' expected - found '%s'",
  1399.             GlblLineCount, TempCopy);
  1400.         break;
  1401.     case IP_ERR_CLOSE_PAREN_EXPECTED:
  1402.         sprintf(GlblTokenError, "Line %d: ']' expected - found '%s'",
  1403.             GlblLineCount, TempCopy);
  1404.         break;
  1405.     case IP_ERR_LIST_COMP_UNDEF:
  1406.         sprintf(GlblTokenError, "Line %d: Undefined list element - \"%s\"",
  1407.             GlblLineCount, TempCopy);
  1408.         break;
  1409.     case IP_ERR_UNDEF_EXPR_HEADER:
  1410.         sprintf(GlblTokenError, "Line %d: Undefined TOKEN - \"%s\"",
  1411.             GlblLineCount, TempCopy);
  1412.         break;
  1413.     case IP_ERR_PT_TYPE_EXPECTED:
  1414.         sprintf(GlblTokenError, "Line %d: Point type expected",
  1415.             GlblLineCount);
  1416.         break;
  1417.     case IP_ERR_OBJECT_EMPTY:
  1418.         sprintf(GlblTokenError, "Line %d: Empty object found",
  1419.             GlblLineCount);
  1420.         break;
  1421.     case IP_ERR_FILE_EMPTY:
  1422.         sprintf(GlblTokenError, "Line %d: Empty object found",
  1423.             GlblLineCount);
  1424.         break;
  1425.     case IP_ERR_MIXED_TYPES:
  1426.         sprintf(GlblTokenError,
  1427.             "Line %d: Mixed data types in same object",
  1428.             GlblLineCount);
  1429.         break;
  1430.     case IP_STR_NOT_IN_QUOTES:
  1431.         sprintf(GlblTokenError,
  1432.             "Line %d: String not in quotes (%s)",
  1433.             GlblLineCount, TempCopy);
  1434.         break;
  1435.     case IP_ERR_OBJECT_EXPECTED:
  1436.         sprintf(GlblTokenError,
  1437.             "Line %d: 'OBJECT' expected, found '%s'",
  1438.             GlblLineCount, TempCopy);
  1439.         break;
  1440.     case IP_ERR_CAGD_LIB_ERR:
  1441.         sprintf(GlblTokenError, "Line %d: %s",
  1442.             GlblLineCount, TempCopy);
  1443.         break;
  1444.     case IP_ERR_STACK_OVERFLOW:
  1445.         sprintf(GlblTokenError, "Line %d: Parser Stack overflow",
  1446.             GlblLineCount);
  1447.         break;
  1448.     case IP_ERR_DEGEN_POLYGON:
  1449.         sprintf(GlblTokenError, "Line %d: Degenerate polygon",
  1450.             GlblLineCount);
  1451.         break;
  1452.     case IP_ERR_DEGEN_NORMAL:
  1453.         sprintf(GlblTokenError, "Line %d: Degenerate normal",
  1454.             GlblLineCount);
  1455.         break;
  1456.     case IP_ERR_SOCKET_BROKEN:
  1457.         sprintf(GlblTokenError, "Line %d: Socket connection is broken",
  1458.             GlblLineCount);
  1459.         break;
  1460.     case IP_ERR_SOCKET_TIME_OUT:
  1461.         sprintf(GlblTokenError, "Line %d: Socket connection is broken",
  1462.             GlblLineCount);
  1463.         break;
  1464.     case IP_ERR_BIN_UNDEF_OBJ:
  1465.         sprintf(GlblTokenError, "Binary stream: Undefined object");
  1466.         break;
  1467.     default:
  1468.         sprintf(GlblTokenError,
  1469.             "Line %d: Data file parser - undefined error",
  1470.             GlblLineCount);
  1471.         break;
  1472.     }
  1473.  
  1474.     *ErrorMsg = GlblTokenError;
  1475.  
  1476.     return TRUE;
  1477. }
  1478.  
  1479. /*****************************************************************************
  1480. *   Routine to test if the given polygon is convex or not.             *
  1481. * Algorithm: The polygon is convex iff the normals generated from cross      *
  1482. * products of two consecutive edges points to the same direction. The same   *
  1483. * direction is tested by a positive dot product.                 *
  1484. *****************************************************************************/
  1485. int IritPrsrIsConvexPolygon(IPPolygonStruct *Pl)
  1486. {
  1487.     RealType Size, V1[3], V2[3], LastNormal[3], Normal[3];
  1488.     IPVertexStruct *VNext, *VNextNext,
  1489.     *V = Pl -> PVertex;
  1490.  
  1491.     LastNormal[0] = LastNormal[1] = LastNormal[2] = 0.0;
  1492.  
  1493.     do {
  1494.     if ((VNext = V -> Pnext) == NULL)
  1495.         VNext = Pl -> PVertex;
  1496.     if ((VNextNext = VNext -> Pnext) == NULL)
  1497.         VNextNext = Pl -> PVertex;
  1498.  
  1499.     PT_SUB(V1, VNext -> Coord, V -> Coord);
  1500.     if ((Size = PT_LENGTH(V1)) > EPSILON) {
  1501.         Size = 1.0 / Size;
  1502.         PT_SCALE(V1, Size);
  1503.     }
  1504.     PT_SUB(V2, VNextNext -> Coord, VNext -> Coord);
  1505.     if ((Size = PT_LENGTH(V2)) > EPSILON) {
  1506.         Size = 1.0 / Size;
  1507.         PT_SCALE(V2, Size);
  1508.     }
  1509.     CROSS_PROD(Normal, V1, V2);
  1510.  
  1511.     if (V != Pl -> PVertex) {
  1512.         if (PT_LENGTH(Normal) > CONVEX_EPSILON &&
  1513.         DOT_PROD(Normal, LastNormal) < -CONVEX_EPSILON)
  1514.         return FALSE;
  1515.     }
  1516.  
  1517.     PT_COPY(LastNormal, Normal);
  1518.  
  1519.     V = VNext;
  1520.     }
  1521.     while (V != Pl -> PVertex && V != NULL);
  1522.  
  1523.     return TRUE;
  1524. }
  1525.  
  1526. /*****************************************************************************
  1527. * Routine to print the data from given object into stdout.             *
  1528. *****************************************************************************/
  1529. void IritPrsrStdoutObject(IPObjectStruct *PObj)
  1530. {
  1531.     IritPrsrOutputFile = stdout;
  1532.  
  1533.     IritPrsrPutAllObjects(PObj, 0);
  1534. }
  1535.  
  1536. /*****************************************************************************
  1537. * Routine to print the data from given object into given file FileName.         *
  1538. * If FileName is NULL or empty, print to screen using IritPrsrPrintFunc      *
  1539. *****************************************************************************/
  1540. void IritPrsrPutObject(FILE *f, IPObjectStruct *PObj)
  1541. {
  1542.     /* If the following gain control and is non zero - its from error! */
  1543.     if (setjmp(_IritPrsrLongJumpBuffer) != 0)
  1544.     return;
  1545.  
  1546.     IritPrsrOutputFile = f;
  1547.  
  1548.     if (_IritPrsrReadWriteBinary)
  1549.         IritPrsrPutBinObject(f, PObj);
  1550.     else
  1551.     IritPrsrPutAllObjects(PObj, 0);
  1552. }
  1553.  
  1554. /*****************************************************************************
  1555. * Same as fprintf but with indentation. Prints into global             *
  1556. * IritPrsrOutputFile unless it is NULL in which it prints to the specified   *
  1557. * function IritPrsrPrintFunc.                             *
  1558. *****************************************************************************/
  1559. #ifdef USE_VARARGS
  1560. static void IFprintf(int Indent, char *va_alist, ...)
  1561. {
  1562.     char *Format, Line[LINE_LEN_LONG];
  1563.     int i;
  1564.     va_list ArgPtr;
  1565.  
  1566.     va_start(ArgPtr);
  1567.     Format = va_arg(ArgPtr, char *);
  1568. #else
  1569. static void IFprintf(int Indent, char *Format, ...)
  1570. {
  1571.     char Line[LINE_LEN_LONG];
  1572.     int i;
  1573.     va_list ArgPtr;
  1574.  
  1575.     va_start(ArgPtr, Format);
  1576. #endif /* USE_VARARGS */
  1577.  
  1578.     if (_IritPrsrWriteSocket) {
  1579.     /* No need for indentation if writing to a socket. */
  1580.     vsprintf(Line, Format, ArgPtr);
  1581.     SocServerWriteLine(Line, strlen(Line));
  1582.     }
  1583.     else
  1584.     {
  1585.     for (i = 0; Indent >= 8; i++, Indent -= 8)
  1586.         Line[i] = '\t';
  1587.     for ( ; i < Indent; i++)
  1588.         Line[i] = ' ';
  1589.     vsprintf(&Line[i], Format, ArgPtr);
  1590.  
  1591.     if (IritPrsrOutputFile != NULL)
  1592.         fputs(Line, IritPrsrOutputFile);
  1593.     else
  1594.         IritPrsrPrintFunc(Line);
  1595.     }
  1596.  
  1597.     va_end(ArgPtr);
  1598. }
  1599.  
  1600. /*****************************************************************************
  1601. * Routine to print the data from given geometry object.                 *
  1602. *****************************************************************************/
  1603. static void IritPrsrPutAllObjects(IPObjectStruct *PObj, int Indent)
  1604. {
  1605.     int i, IsRational, NumCoords;
  1606.     char Str[LINE_LEN],
  1607.     *ErrStr = NULL;
  1608.     CagdRType *Coords;
  1609.     IPObjectStruct *PObjTmp;
  1610.     IPPolygonStruct *PPolygon;
  1611.     IPVertexStruct *PVertex;
  1612.     IPAttributeStruct
  1613.     *Attr = AttrTraceAttributes(PObj -> Attrs);
  1614.  
  1615.     if (Attr) {
  1616.     IFprintf(Indent, "[OBJECT\n");
  1617.  
  1618.     while (Attr) {
  1619.         IFprintf(Indent + 4, "%s\n", Attr2String(Attr));
  1620.         Attr = AttrTraceAttributes(NULL);
  1621.     }
  1622.  
  1623.     IFprintf(Indent + 4,
  1624.          "%s\n", strlen(PObj -> Name) ? PObj -> Name : "NONE");
  1625.     }
  1626.     else {
  1627.     IFprintf(Indent, "[OBJECT %s\n",
  1628.              strlen(PObj -> Name) ? PObj -> Name : "NONE");
  1629.     }
  1630.     Indent += 4;
  1631.  
  1632.     switch (PObj -> ObjType) {
  1633.     case IP_OBJ_POLY:
  1634.         for (PPolygon = PObj -> U.Pl;
  1635.          PPolygon != NULL;
  1636.          PPolygon = PPolygon -> Pnext) {
  1637.         if (PPolygon -> PVertex == NULL)
  1638.             continue;
  1639.  
  1640.         if (IP_IS_POLYLINE_OBJ(PObj))
  1641.             IFprintf(Indent, "[POLYLINE ");
  1642.         else if (IP_IS_POINTLIST_OBJ(PObj))
  1643.             IFprintf(Indent, "[POINTLIST ");
  1644.         else
  1645.             IFprintf(Indent, "[POLYGON [PLANE %s %s %s %s] ",
  1646.             Real2Str(PPolygon -> Plane[0]),
  1647.             Real2Str(PPolygon -> Plane[1]),
  1648.             Real2Str(PPolygon -> Plane[2]),
  1649.             Real2Str(PPolygon -> Plane[3]));
  1650.  
  1651.         for (Attr = AttrTraceAttributes(PPolygon -> Attrs);
  1652.              Attr != NULL;
  1653.              Attr = AttrTraceAttributes(NULL))
  1654.             IFprintf(Indent + 4, "%s\n", Attr2String(Attr));
  1655.  
  1656.         for (PVertex = PPolygon -> PVertex -> Pnext, i = 1;
  1657.              PVertex != PPolygon -> PVertex && PVertex != NULL;
  1658.              PVertex = PVertex -> Pnext, i++);
  1659.         IFprintf(Indent + 4, "%d\n", i);
  1660.  
  1661.         PVertex = PPolygon -> PVertex;
  1662.         do {             /* Assume at least one edge in polygon! */
  1663.             IFprintf(Indent + 4, "[");
  1664.             
  1665.             for (Attr = AttrTraceAttributes(PVertex -> Attrs);
  1666.              Attr != NULL;
  1667.              Attr = AttrTraceAttributes(NULL))
  1668.             IFprintf(Indent + 4, "%s\n", Attr2String(Attr));
  1669.  
  1670.             if (IP_IS_POLYLINE_OBJ(PObj) ||
  1671.             (IP_IS_POLYGON_OBJ(PObj) &&
  1672.              PT_APX_EQ(PPolygon -> Plane, PVertex -> Normal)))
  1673.             IFprintf(0, "%s%s %s %s]\n",
  1674.                 IP_IS_INTERNAL_VRTX(PVertex) ? "[INTERNAL] " : "",
  1675.                 Real2Str(PVertex -> Coord[0]),
  1676.                 Real2Str(PVertex -> Coord[1]),
  1677.                 Real2Str(PVertex -> Coord[2]));
  1678.             else if (IP_IS_POINTLIST_OBJ(PObj))
  1679.             IFprintf(0, "%s %s %s]\n",
  1680.                 Real2Str(PVertex -> Coord[0]),
  1681.                 Real2Str(PVertex -> Coord[1]),
  1682.                 Real2Str(PVertex -> Coord[2]));
  1683.             else
  1684.             IFprintf(0, "%s[NORMAL %s %s %s] %s %s %s]\n",
  1685.                 IP_IS_INTERNAL_VRTX(PVertex) ? "[INTERNAL] " : "",
  1686.                 Real2Str(PVertex -> Normal[0]),
  1687.                 Real2Str(PVertex -> Normal[1]),
  1688.                 Real2Str(PVertex -> Normal[2]),
  1689.                 Real2Str(PVertex -> Coord[0]),
  1690.                 Real2Str(PVertex -> Coord[1]),
  1691.                 Real2Str(PVertex -> Coord[2]));
  1692.  
  1693.             PVertex = PVertex -> Pnext;
  1694.         }
  1695.         while (PVertex != PPolygon -> PVertex && PVertex != NULL);
  1696.         IFprintf(Indent, "]\n");           /* Close the polygon. */
  1697.         }
  1698.         break;
  1699.     case IP_OBJ_NUMERIC:
  1700.         IFprintf(Indent, "[NUMBER %s]\n", Real2Str(PObj -> U.R));
  1701.         break;
  1702.     case IP_OBJ_POINT:
  1703.         IFprintf(Indent, "[POINT %s %s %s]\n",
  1704.              Real2Str(PObj -> U.Pt[0]),
  1705.              Real2Str(PObj -> U.Pt[1]),
  1706.              Real2Str(PObj -> U.Pt[2]));
  1707.         break;
  1708.     case IP_OBJ_VECTOR:
  1709.         IFprintf(Indent, "[VECTOR %s %s %s]\n",
  1710.              Real2Str(PObj -> U.Vec[0]),
  1711.              Real2Str(PObj -> U.Vec[1]),
  1712.              Real2Str(PObj -> U.Vec[2]));
  1713.         break;
  1714.     case IP_OBJ_PLANE:
  1715.         IFprintf(Indent, "[PLANE %s %s %s %s]\n",
  1716.              Real2Str(PObj -> U.Plane[0]),
  1717.              Real2Str(PObj -> U.Plane[1]),
  1718.              Real2Str(PObj -> U.Plane[2]),
  1719.              Real2Str(PObj -> U.Plane[3]));
  1720.         break;
  1721.     case IP_OBJ_CTLPT:
  1722.         Coords = PObj -> U.CtlPt.Coords;
  1723.         IsRational = CAGD_IS_RATIONAL_PT(PObj -> U.CtlPt.PtType);
  1724.         NumCoords = CAGD_NUM_OF_PT_COORD(PObj -> U.CtlPt.PtType);
  1725.  
  1726.         sprintf(Str, "[CTLPT %c%d %s", IsRational ? 'P' : 'E', NumCoords,
  1727.             IsRational ? Real2Str(Coords[0]) : "");
  1728.         
  1729.         for (i = 1; i <= NumCoords; i++) {
  1730.         strcat(Str, " ");
  1731.             strcat(Str, Real2Str(Coords[i]));
  1732.         }
  1733.         strcat(Str,"]\n");
  1734.         IFprintf(Indent, Str);
  1735.         break;
  1736.     case IP_OBJ_MATRIX:
  1737.         IFprintf(Indent, "[MATRIX\n");
  1738.         for (i = 0; i < 4; i++)
  1739.         IFprintf(Indent + 8, "%s %s %s %s%s\n",
  1740.              Real2Str((*PObj -> U.Mat)[i][0]),
  1741.              Real2Str((*PObj -> U.Mat)[i][1]),
  1742.              Real2Str((*PObj -> U.Mat)[i][2]),
  1743.              Real2Str((*PObj -> U.Mat)[i][3]),
  1744.              i == 3 ? "]" : "");
  1745.         break;
  1746.     case IP_OBJ_STRING:
  1747.         IFprintf(Indent, "[STRING \"%s\"]\n", PObj -> U.Str);
  1748.         break;
  1749.     case IP_OBJ_LIST_OBJ:
  1750.         for (i = 0; (PObjTmp = ListObjectGet(PObj, i)) != NULL; i++)
  1751.         IritPrsrPutAllObjects(PObjTmp, Indent);
  1752.         break;
  1753.     case IP_OBJ_CURVE:
  1754.             CagdCrvWriteToFile2(PObj -> U.Crvs, IritPrsrOutputFile,
  1755.                 Indent, NULL, &ErrStr);
  1756.         break;
  1757.     case IP_OBJ_SURFACE:
  1758.         CagdSrfWriteToFile2(PObj -> U.Srfs, IritPrsrOutputFile,
  1759.                 Indent, NULL, &ErrStr);
  1760.         break;
  1761.     default:
  1762.         IritPrsrFatalError("Attemp to print undefine object type.");
  1763.         break;
  1764.     }
  1765.  
  1766.     Indent -= 4;
  1767.     IFprintf(Indent, "]\n");                /* Close the object. */
  1768.  
  1769.     if (ErrStr != NULL)
  1770.     IritPrsrParserAbort(IP_ERR_CAGD_LIB_ERR, ErrStr);
  1771. }
  1772.  
  1773. /*****************************************************************************
  1774. * Convert a real number into a string.                         *
  1775. * The routine maintains 6 different buffers simultanuously so up to 6 calls  *
  1776. * can be issued from same printf...                         *
  1777. *****************************************************************************/
  1778. static char *Real2Str(RealType R)
  1779. {
  1780.     static int j, k,
  1781.     i = 0;
  1782.     static char Buffer[6][LINE_LEN_SHORT], Line[LINE_LEN];
  1783.  
  1784.     if (ABS(R) < ZERO_NUM_EPSILON)
  1785.     R = 0.0;                /* Round off very small numbers. */
  1786.  
  1787.     sprintf(Buffer[i], GlblFloatFormat, R);
  1788.  
  1789.     for (k = 0; !isdigit(Buffer[i][k]) && k < LINE_LEN; k++);
  1790.     if (k >= LINE_LEN) {
  1791.     sprintf(Line, "Conversion of real number (%f) failed.", R);
  1792.     IritPrsrFatalError(Line);
  1793.     }
  1794.  
  1795.     for (j = strlen(Buffer[i]) - 1; Buffer[i][j] == ' ' && j > k; j--);
  1796.     if (strchr(Buffer[i], '.') != NULL)
  1797.     for (; Buffer[i][j] == '0' && j > k; j--);
  1798.     Buffer[i][j+1] = 0;
  1799.  
  1800.     j = i;
  1801.     i = (i + 1) % 6;
  1802.     return Buffer[j];
  1803. }
  1804.  
  1805. /*****************************************************************************
  1806. * Returns a pointer to last vertex of a list.                     *
  1807. *****************************************************************************/
  1808. IPVertexStruct *IritPrsrGetLastVrtx(IPVertexStruct *VList)
  1809. {
  1810.     return IritPrsrGetPrevVrtx(VList, NULL);
  1811. }
  1812.  
  1813. /*****************************************************************************
  1814. * Returns a pointer to previous vertex in VList to V.                 *
  1815. *****************************************************************************/
  1816. IPVertexStruct *IritPrsrGetPrevVrtx(IPVertexStruct *VList, IPVertexStruct *V)
  1817. {
  1818.     IPVertexStruct
  1819.     *VHead = VList;
  1820.  
  1821.     if (VList == NULL || VList == V)
  1822.     return NULL;
  1823.  
  1824.     for ( ;
  1825.       VList != NULL && VList -> Pnext != V && VList -> Pnext != VHead;
  1826.       VList = VList -> Pnext);
  1827.  
  1828.     return VList;
  1829. }
  1830.  
  1831. /*****************************************************************************
  1832. * Returns a pointer to last polygon/line of a list.                 *
  1833. *****************************************************************************/
  1834. IPPolygonStruct *IritPrsrGetLastPoly(IPPolygonStruct *PList)
  1835. {
  1836.     return IritPrsrGetPrevPoly(PList, NULL);
  1837. }
  1838.  
  1839. /*****************************************************************************
  1840. * Returns a pointer to previous poly in PList to P.                 *
  1841. *****************************************************************************/
  1842. IPPolygonStruct *IritPrsrGetPrevPoly(IPPolygonStruct *PList, IPPolygonStruct *P)
  1843. {
  1844.     if (PList == NULL || PList == P)
  1845.     return NULL;
  1846.  
  1847.     for ( ; PList != NULL && PList -> Pnext != P; PList = PList -> Pnext);
  1848.  
  1849.     return PList;
  1850. }
  1851.  
  1852. /*****************************************************************************
  1853. * Returns a pointer to last polygon/line of an object.                 *
  1854. *****************************************************************************/
  1855. IPObjectStruct *IritPrsrGetLastObj(IPObjectStruct *OList)
  1856. {
  1857.     return IritPrsrGetPrevObj(OList, NULL);
  1858. }
  1859.  
  1860. /*****************************************************************************
  1861. * Returns a pointer to previous object in OList to O.                 *
  1862. *****************************************************************************/
  1863. IPObjectStruct *IritPrsrGetPrevObj(IPObjectStruct *OList, IPObjectStruct *O)
  1864. {
  1865.     if (OList == NULL || OList == O)
  1866.     return NULL;
  1867.  
  1868.     for ( ; OList != NULL && OList -> Pnext != O; OList = OList -> Pnext);
  1869.     if (OList == NULL)
  1870.         return NULL;
  1871.  
  1872.     return OList;
  1873. }
  1874.  
  1875. /*****************************************************************************
  1876. * Returns the length of a list of vertices.                     *
  1877. *****************************************************************************/
  1878. int IritPrsrVrtxListLen(IPVertexStruct *V)
  1879. {
  1880.     int i;
  1881.  
  1882.     for (i = 0; V != NULL; i++, V = V -> Pnext);
  1883.  
  1884.     return i;
  1885. }
  1886.  
  1887. /*****************************************************************************
  1888. * Returns the length of a list of polys.                     *
  1889. *****************************************************************************/
  1890. int IritPrsrPolyListLen(IPPolygonStruct *P)
  1891. {
  1892.     int i;
  1893.  
  1894.     for (i = 0; P != NULL; i++, P = P -> Pnext);
  1895.  
  1896.     return i;
  1897. }
  1898.  
  1899. /*****************************************************************************
  1900. * Returns the length of a list of objects.                     *
  1901. *****************************************************************************/
  1902. int IritPrsrObjListLen(IPObjectStruct *O)
  1903. {
  1904.     int i;
  1905.  
  1906.     for (i = 0; O != NULL; i++, O = O -> Pnext);
  1907.  
  1908.     return i;
  1909. }
  1910.  
  1911. /*****************************************************************************
  1912. * Sets the printing function to call if FileName to print to is NULL.         *
  1913. *****************************************************************************/
  1914. void IritPrsrSetPrintFunc(IritPrsrPrintFuncType PrintFunc)
  1915. {
  1916.     IritPrsrPrintFunc = PrintFunc;
  1917.     CagdSetCagdFprintf(PrintFunc);
  1918. }
  1919.  
  1920. /*****************************************************************************
  1921. * Sets the floating point printing format.                     *
  1922. *****************************************************************************/
  1923. void IritPrsrSetFloatFormat(char *FloatFormat)
  1924. {
  1925.     GlblFloatFormat = FloatFormat;
  1926.     CagdSetFloatFormat(FloatFormat);
  1927. }
  1928.  
  1929. /*****************************************************************************
  1930. * Sets the file format to binary.                         *
  1931. *****************************************************************************/
  1932. void IritPrsrSetBinaryFormat(int BinFormat)
  1933. {
  1934.     _IritPrsrReadWriteBinary = BinFormat;
  1935. }
  1936.